/*
	Copyright (c) 2012 by karmaleaving@qq.com. All rights RESERVED.
*/

#ifndef __SHARED_PTR_H_VERSION_KL__
#define __SHARED_PTR_H_VERSION_KL__
#include "throw.h"
#include "./memory.h" // for class <auto_ptr>
KL_BEGIN
template<class Type>
class shared_ptr
{
	protected:
		struct inner_data;
		inner_data * _data;
	public:
		typedef Type Type;
		shared_ptr(Type * val = 0)	
			: _data(new inner_data<Type>(val)) 
		{}
		~shared_ptr()	
		{
			_data->release(); 
		}
		shared_ptr(shared_ptr<Type> const &other)
			: _data(other._data->reference())
		{
		}
		void operator = (shared_ptr<Type> const &other)
		{
			_data->release();
			_data = other._data->reference();
		}
		void operator = (Type * val)
		{
			_data->release();
			_data = new inner_data<Type>(val);
		}
		bool operator == (shared_ptr<Type> const &other) const
		{
			return _data == other._data;
		}
		bool operator == (const Type * const other) const
		{
			return _data->visit() == other;
		}
		bool valid() const
		{
			return (_data->visit() != 0);
		}
		Type & operator * ()
		{
			ASSERT(valid());
			return *(_data->visit());
		}
		const Type & operator * () const
		{
			ASSERT(valid());
			return *(_data->visit());
		}
		Type & operator -> ()
		{
			ASSERT(valid());
			return *(_data->visit());
		}
		const Type & operator -> () const
		{
			ASSERT(valid());
			return *(_data->visit());
		}
	protected:
		struct inner_data
		{
			protected:
				Type * _value;
				int _ref;
				inner_data(inner_data const &);
				~inner_data() 
				{
					DELETEIT(_value); 
				}
			public:
				inner_data(Type *val) : _value(val), _ref(1) 
				{ 
				}
				Type * visit() const 
				{ 
					return _value; 
				}
				inner_data<Type> * reference()   
				{ 
					++_ref; return this; 
				}
				void release() 
				{ 
					if (!--_ref) delete this; 
				}
		};
};
KL_BEGIN
#endif // __SHARED_PTR_H_VERSION_KL__
